package com.zjw.zy.common;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zhongjiwei
 * <p>
 * 简单线程池
 */
public final class ThreadPool {

    private static final RejectHandler sDefaultRejectHandler = (task, pool) -> {
        throw new RuntimeException("reject task and throw a exception!");
    };

    private static final ThreadFactory sDefaultThreadFactory = worker -> {
        Thread thread = new Thread(worker.mTask, worker.mWorkName);
        thread.setDaemon(false);
        thread.setPriority(Thread.NORM_PRIORITY);
        return thread;
    };

    private final RejectHandler mRejectHandler;
    private final ThreadFactory mThreadFactory;
    private final Lock mLock = new ReentrantLock();
    private final int mCoreSize;
    //循环队列前后指针
    private int mLp = 0;
    private int mRp = 0;
    private Worker[] mCorePool;
    private int mState = -1;


    public ThreadPool(int coreSize) {
        this(coreSize, sDefaultRejectHandler);
    }

    public ThreadPool(int coreSize, RejectHandler handler) {
        this(coreSize, handler, sDefaultThreadFactory);
    }

    public ThreadPool(int coreSize, RejectHandler handler, ThreadFactory factory) {
        this.mCoreSize = coreSize;
        this.mRejectHandler = handler;
        this.mThreadFactory = factory;
        initPool();
    }

    private void initPool() {
        mLock.lock();
        //初始化核心线程池
        mCorePool = new Worker[mCoreSize];
        mLp = 0;
        mRp = mCoreSize - 1;
        for (int i = 0; i < mCoreSize; i++) {
            mCorePool[i] = new Worker("core-thread-" + i);
        }
        mState = 921;
        mLock.unlock();
    }

    public void execute(Runnable task) {
        if (mState == -1) {
            return;
        }
        Worker worker = offerCorePoolThread();
        if (worker != null) {
            executeOnCore(worker, task);
            return;
        }
        mRejectHandler.onRejectExecute(task, this);
    }

    public void shutDown() {
        mLock.lock();
        mState = -1;
        for (int i = 0; i < mCorePool.length; i++) {
            mCorePool[i].stop();
            mCorePool[i] = null;
        }
        mLock.unlock();
    }

    private void executeOnCore(Worker worker, Runnable task) {
        if (mState == -1) {
            return;
        }
        worker.setTask(task);
        worker.start();
    }

    private Worker offerCorePoolThread() {
        mLock.lock();
        Worker worker = null;
        if (mLp <= mRp) {
            worker = mCorePool[mLp % mCoreSize];
            if (worker.getState() == Worker.NOT_SET) {
                mLp++;
            } else {
                worker = null;
            }
        }
        mLock.unlock();
        return worker;
    }

    private class Worker {

        static final int NOT_SET = 0;
        static final int READY_RUN = 1;
        static final int RUNNING = 2;
        private final String mWorkName;
        private final AtomicInteger mState = new AtomicInteger(NOT_SET);
        private Runnable mTask;

        private Thread mThread;

        private Worker(String name) {
            mWorkName = name;
        }

        public int getState() {
            return mState.get();
        }

        private void setTask(Runnable task) {
            if (this.mState.get() != NOT_SET) {
                return;
            }
            mState.set(READY_RUN);
            mTask = () -> {
                task.run();
                reset();
            };
            mThread = ThreadPool.this.mThreadFactory.onOfferThread(this);
        }

        private void reset() {
            mState.set(NOT_SET);
            ThreadPool.this.recycleWorker(this);
        }

        private void start() {
            if (mState.get() != READY_RUN) {
                return;
            }
            mState.set(RUNNING);
            mThread.start();
        }

        public void stop() {
            if (mState.get() == NOT_SET) {
                return;
            }
            if (mState.get() == READY_RUN) {
                mState.set(NOT_SET);
                mThread = null;
                return;
            }

            mThread.interrupt();
            mThread = null;
        }
    }

    private void recycleWorker(Worker worker) {
        mLock.lock();
        mCorePool[(++mRp) % mCoreSize] = worker;
        mLock.unlock();
    }


    //拒绝策略
    public interface RejectHandler {
        void onRejectExecute(Runnable task, ThreadPool pool);
    }

    //线程工厂
    public interface ThreadFactory {
        Thread onOfferThread(Worker worker);
    }

    /**
     * 测试
     */
    public static void main(String[] args) throws Exception {
        Thread.setDefaultUncaughtExceptionHandler((t, e) -> System.out.println("捕获你" + e.getMessage()));

        ThreadPool threadPool = new ThreadPool(10, (task, pool) -> {
            //do nothing
            System.out.println("任务被拒绝");
        });

        for (int i = 0; i < 100; i++) {
            if (i == 99) {
                System.out.println("shutDown线程池！");
                threadPool.shutDown();
                return;
            }
            threadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
        }
        Thread.currentThread().join();
    }
}
